#include <iterator>
#include "MarkupSTL.h"
#include "global.h"
#include "def.h"
#include "Game.h"
#include "RedisClient.h"
#include "Logic.h"
#include "json.h"
#include "globalExtern.h"
#include "Host.h"
#include "NodeServer.h"

CGameServer::CGameServer():m_keyIndex(0)
{
	m_pHost = NULL;
}

CGameServer::~CGameServer()
{
}

bool CGameServer::InitGame()
{
	StartTimer(TIMERID_GAME_USERINFO_UPDATE, 5);
	return true;
}

int CGameServer::OnBYTimeOut(int Timerid)
{
	switch (Timerid)
	{
	case TIMERID_GAME_USERINFO_UPDATE:
		ProcGameUserinfoUpdateSet();
		break;
	default:
		break;
	}
	return 0;
}


int CGameServer::ProcessPacket(SocketHandler* pHandler, NETInputPacket* inputPkg)
{

	//int cmd = inputPkg->GetCmdType();

	return 0;
}

int CGameServer::ProcEventPublishService(int ev_id, SpiderEvent* pEvent)
{
	if (!(pEvent && pEvent->evParam.ptr))
		return -1;

	ServiceConf* pserviceConf = (ServiceConf*)pEvent->evParam.ptr;
	if (SERVER_TYPE_GAME_USERINFO_DB_UPDATE == pserviceConf->server_type)
	{
		ServiceTypeList::const_iterator itor = m_pHost->m_pNode->m_serviceTypeList.find(SERVER_TYPE_GAME_USERINFO_DB_UPDATE);
		if (m_pHost->m_pNode->m_serviceTypeList.end() != itor && itor->second.size() > 0)
		{
			m_upuidSetKeys.clear();
			m_keyIndex = 0;
			unsigned int index = 0;
			for (ServiceVect::const_iterator itor1 = itor->second.begin(); itor->second.end() != itor1; ++itor1, ++index)
			{
				if (TGlobal::_svid == itor1->svid)
				{
					break;
				}
			}


			if (index < itor->second.size())
			{
				unsigned int nodecount = itor->second.size();

				log_debug("srv id,%d,index,%d,service num,%u", TGlobal::_svid, (int)index, nodecount);
				char szkey[50] = { 0 };
				for (size_t i = 0; i < MOD_DENOMINATOR; ++i)
				{
					if (index == i % nodecount)
					{
						::memset(szkey, 0, sizeof(szkey));
						::snprintf(szkey, sizeof(szkey) - 1, "game_userinfo_upuid_set:%d", (int)i);
						m_upuidSetKeys.push_back(std::string(szkey));
						log_debug("proc key,%s", szkey);
					}
				}
			}
			else
			{
				log_error("service find no srv id,srv id,%d", TGlobal::_svid);
			}
			log_debug("service pulish ready, srv id,%d", TGlobal::_svid);
		}
		else
		{
			log_error("service pulish not ready");
		}
	}
	return 0;
}


int CGameServer::ProcGameUserinfoUpdateSet()
{
	StartTimer(TIMERID_GAME_USERINFO_UPDATE, 20);

	if (m_upuidSetKeys.size() > 0)
	{
		std::set<int> excludeset;
		bool moveflag = false;
		for (int i = 0; i < 5000; ++i)
		{
			std::vector<unsigned int> vectuid;
			GetGameUserinfoUpuidSet(m_upuidSetKeys[m_keyIndex], vectuid);
			if (vectuid.size() > 0)
			{
				for (std::vector<unsigned int>::const_iterator itor = vectuid.begin(); itor != vectuid.end(); ++itor)
				{
					UpdateUserAllData(*itor);
				}
			}
			else
			{
				excludeset.insert(m_keyIndex);
				log_debug("set %u empty", m_keyIndex);
				if (excludeset.size() >= m_upuidSetKeys.size())
				{
					moveflag = false;
					log_debug("all set empty,%d", (int16_t)excludeset.size());
					break;
				}
				else
				{
					m_keyIndex = (m_keyIndex + 1) % (int)m_upuidSetKeys.size();
					moveflag = true;
				}
			}
		}

		if (!moveflag)
		{
			m_keyIndex = (m_keyIndex + 1) % (int)m_upuidSetKeys.size();
		}	
	}
	else
	{
		log_error("no updateuid set key");
	}

	return 0;
}

bool CGameServer::GetGameUserinfoUpuidSet(const std::string& setkey, std::vector<unsigned int>& vectuid)
{
	string strVal;

	m_GameUserinfoRedis->Spop(setkey, &strVal);
	log_debug("spop,%s, val,%s", setkey.c_str(), strVal.c_str());
	if (!strVal.empty())
	{
		unsigned int uid = ::strtoul(strVal.c_str(), NULL, 10); //::atol(strVal.c_str());
		vectuid.push_back(uid);
	}

	return true;
}

bool CGameServer::UpdateUserAllData(const unsigned int uid)
{
	if (uid <= 0)
		return false;

	std::map<std::string, std::string> mapVal;
	std::string redisKey = "game_userinfo:" + std::to_string(uid);
	m_GameUserinfoRedis->Hgetall(redisKey, &mapVal);
	if (mapVal.size() <= 0)
		return false;
	
	for (std::map<std::string, std::string>::const_iterator itor = mapVal.begin(); mapVal.end() != itor; ++itor)
	{
		int game_id = std::atoi(itor->first.c_str());
		if (game_id <= 0)
		{
			continue;
		}
		log_debug("update uid = %u,game_id = %u", uid, game_id);
		m_dbHandler.UpdateUserAllData(uid, game_id, itor->second);
	}
	return false;
}